package com.zecan.blog.websocket;

import cn.hutool.json.JSONUtil;
import com.zecan.blog.rabbitmq.BlogMqProducer;
import com.zecan.blog.rabbitmq.event.ChatRoomEvent;
import com.zecan.blog.utils.BlogConstant;
import com.zecan.blog.utils.SpringUtils;
import com.zecan.blog.utils.StringUtils;
import com.zecan.blog.vo.chatroom.ChatRoom;
import com.zecan.blog.vo.chatroom.ChatRoomMsgVo;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.websocket.OnClose;
import javax.websocket.OnMessage;
import javax.websocket.OnOpen;
import javax.websocket.Session;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

/**
 * @author zecan
 * @Description:
 * @ClassName: PrivateChatRoom
 * @date 2022/12/18 15:55
 */

@Slf4j
@ServerEndpoint("/privateWs/{userId}")
@Component
public class PrivateChatRoom {


    private BlogMqProducer blogMqProducer = SpringUtils.getBean(BlogMqProducer.class);

    // 每个用户的session连接
    private Session session;

    // 每个用户的id
    private String userId;

    // 使用 copyOnWriteArraySet  存储每个websocket连接  当前类型是可以保持不重复, 可以用于广播消息传递
    private static CopyOnWriteArrayList<PrivateChatRoom> webSockets = new CopyOnWriteArrayList<>();

    // 使用ConcurrentHashMap 保存每个用户连接信息, 用于对单点消息 或者 群聊消息
    private static ConcurrentHashMap<String, Session> sessionPool = new ConcurrentHashMap<>();


    @OnOpen
    public void onOpen(Session session, @PathParam("userId") String userId) {
        try {
            // 如果当前存在连接则直接将之前的连接关闭
            for (PrivateChatRoom webSocket : webSockets) {
                if (webSocket.userId.equals(userId)) {
                    webSockets.remove(webSocket);
                    sessionPool.remove(userId);
                }
            }
            // 添加连接
            this.session = session;
            this.userId = userId;
            webSockets.add(this);
            sessionPool.put(userId, session);
            log.info(("【websocket消息】有新的连接，总数为:" + webSockets.size()));
        } catch (Exception e) {
            log.error("【websocket】连接异常:" + e.getMessage());
        }
    }


    /**
     * 收到客户端消息后调用的方法
     *
     * @param message
     */
    @OnMessage
    public void onMessage(String message) {
        cn.hutool.json.JSON parse = JSONUtil.parse(message);

        // 获取用户发送的信息
        String userSendMsg = parse.getByPath("message", String.class);
        Integer toUserId = parse.getByPath("toUserId", Integer.class);
        Integer fromUserId = parse.getByPath("fromUserId", Integer.class);
        String avatarUrl = parse.getByPath("toUserAvatarUrl", String.class);
        String nickname = parse.getByPath("nickname", String.class);
        // 单独发消息
        sendMessage(fromUserId, toUserId, userSendMsg, avatarUrl, nickname);

        log.info("【websocket消息】收到客户端消息:" + message);
    }

    public void sendMessage(Integer fromUserId, Integer toUserId, String userSendMsg, String avatarUrl, String nickname) {
        // 获取用户对应的连接
        Session session = sessionPool.get(String.valueOf(toUserId));

        if (session != null && session.isOpen()) {
            try {
                log.info("【websocket消息】 单点消息:" + userSendMsg);
                // 发送消息
                ChatRoom chatRoom = ChatRoom.builder().message(userSendMsg).userId(fromUserId).leftOrRight(1).avatar(avatarUrl).username(nickname).build();
                ChatRoomMsgVo build = ChatRoomMsgVo.builder().chatRoom(chatRoom).isNewMsg(true).build();
                // 发送给消息队列添加聊天记录
                blogMqProducer.sendChatMessage(BlogConstant.RABBITMQ_EXCHANGE, BlogConstant.RABBITMQ_CHATROOM_ROUTING_KEY,
                        ChatRoomEvent.builder()
                                .chatRoomType(1)
                                .content(userSendMsg)
                                .userId(fromUserId)
                                .users(StringUtils.concatChattingUsers(fromUserId, toUserId))
                                .build());
                // 发送消息
                session.getAsyncRemote().sendText(JSONUtil.toJsonStr(build));
            } catch (Exception e) {
                e.printStackTrace();
            }
            // 如果不在线则直接添加聊天记录即可
        } else {
            blogMqProducer.sendChatMessage(BlogConstant.RABBITMQ_EXCHANGE, BlogConstant.RABBITMQ_CHATROOM_ROUTING_KEY,
                    ChatRoomEvent.builder()
                            .chatRoomType(1)
                            .content(userSendMsg)
                            .userId(fromUserId)
                            .users(StringUtils.concatChattingUsers(fromUserId, toUserId))
                            .build());
        }
    }

    @OnClose
    public void onClose() {
        try {
            webSockets.remove(this);
            sessionPool.remove(this.userId);

            log.info(("【websocket消息】私人聊天室连接断开，总数为:" + webSockets.size()));
        } catch (Exception e) {
            log.error("【websocket】私人聊天室关闭连接异常:" + e.getMessage());
        }
    }
}
